<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <script>
    // 实现一个 监听器， 对data 进行深度监控
    // 开始完善 增加 一个消息管理订阅器的Dep （就是管理消息订阅器的工具， 因为Watcher会有很多）

    class Dep {
      subs = [] // Watcher 订阅者 队列
      static target = null
      addSub(sub) {
        this.subs.push(sub)
      }
      notify(){
        this.subs.forEach(sub => {
          sub.update() // 通知每个订阅者检查更新
        })
      }
    }

    function propsHijack(data,key,val){
      observe(val); //深度劫持 对象所有属性
      var dep = new Dep()
      Object.defineProperty(data,key,{
        enumerable:true, // 允许枚举
        configurable:true, // 允许配置属性
        get() {
           /* 是否需要添加订阅到这 */ 
          if (Dep.target) { // Watcher 初始化触发
            dep.addSub(watcher); // 这里添加一个订阅者
          }
          return val
        },
        set(newVal) {
          val = newVal
          console.log(`属性 ${key} 已经被监听了，现在他的值为 ${newVal.toString()}`)
          dep.notify() // 如果数据变化，通知*所有*订阅者
        }
      })
    }

    /* 监听器 */     
    function observe(data){
      // 没有属性了，或属性不是对象了时 便退出遍历。
      if (!data || (typeof data !== 'object')) { 
        return
      }
      Object.keys(data).forEach( key => {
        propsHijack(data,key,data[key])
      })
    }

    var bzjData = {
      book: {
        name: ''
      },
      name: {
        litter: ''
      }
    }

    // 监听bzjData 但是也只能监听到 原来有的属性，就是修改原有属性有效，新增无效
    observe(bzjData)

  </script>
</body>
</html>
